package com.foton.limiter.construstlimiter.aop;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.foton.limiter.construstlimiter.annotion.FotonRateLimter;
import com.foton.limiter.construstlimiter.entity.ResponseResult;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.json.JSONParser;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author RenPu
 * @Date 2023/3/20 10:55
 * @Version 1.0
 * @Description: 限流注解的切面类
 **/

@Slf4j
@Aspect
@Component
public class FotonLimiterAspect {

    private  static Map<String, RateLimiter> tokenContainer= Maps.newConcurrentMap();

    //1:创建切入点方法
    @Pointcut("@annotation(com.foton.limiter.construstlimiter.annotion.FotonRateLimter)")
    public void fotonRateLimter(){

    }

    //2：创建植入面方法，同时将切入点进行植入
    @SneakyThrows
    @Around("fotonRateLimter()")
    public Object around(ProceedingJoinPoint joinPoint){
        //1：构建request,response对象
        HttpServletRequest request= ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response= ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();

        //2:获取注解标注的资源url
        String uri = request.getRequestURI();
        FotonRateLimter fotonRateLimiter = getFotonRateLimiter(joinPoint);
        if(!Objects.isNull(fotonRateLimiter)){
            RateLimiter rateLimiter=null;

            //进行缓存创建防止频繁创建
            if(!tokenContainer.containsKey(uri)){
                //3:获取注解对象，解析注解的配置内容进行构造令牌对象
              rateLimiter=RateLimiter.create(fotonRateLimiter.tokenRate());
             tokenContainer.putIfAbsent(uri,rateLimiter);
            }
            rateLimiter=tokenContainer.get(uri);
            boolean acquire = rateLimiter.tryAcquire(fotonRateLimiter.timeout(), fotonRateLimiter.timeunit());
            //4:尝试获取令牌

            if(!acquire){
                //5:将获取的令牌的结果，封装成htpp通过Reponse响应出去
                responseResult(response,500,fotonRateLimiter.rateLimiterMsg());
                return null;
            }
        }
        return joinPoint.proceed();
    }


    /**
     * 自定义响应封装结果信息
     * @param response 响应对象
     * @param code     响应码
     * @param returnMsg 响应信息
     * @return
     */
    private void responseResult(HttpServletResponse response, Integer code, String returnMsg) {

        //封装response的头信息
        response.resetBuffer();
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Access-Control-Allow-Origin","*");  //解决跨域
        response.setHeader("Access-Control-Allow-Credentials","true"); //跳过验证

        try(PrintWriter writer=response.getWriter()) {
            //将数据封装进行JSON转换
            ResponseResult result = new ResponseResult(code, returnMsg);
            ObjectMapper mapper = new ObjectMapper();
            String respJson = mapper.writeValueAsString(result);
            log.info("ObjectMapper JSon::::::::::::::::::::"+respJson);
            //写对象进行写出
            writer.write(respJson);

            response.flushBuffer();
        } catch (IOException e) {
            log.error("响应结果出现异常,错误信息：{}",e.getMessage(),e);
            e.printStackTrace();
        }


    }


    //3：获取注解对象
    public FotonRateLimter getFotonRateLimiter(final JoinPoint joinPoint){

        //getTarget().getClass()获取的为RPLimiterController.class, getDeclaredMethods()为里面所有的方法
        Method[] declaredMethods = joinPoint.getTarget().getClass().getDeclaredMethods();

        //注解的配置信息
        String name = joinPoint.getSignature().getName();
        if(!Strings.isNullOrEmpty(name)){
            for (Method method : declaredMethods) {
                FotonRateLimter  fotonRateLimter =method.getAnnotation(FotonRateLimter.class);
                if(!Objects.isNull(fotonRateLimter)&&name.equals(method.getName())){
                    return fotonRateLimter;
                }

            }
        }
          return null;

    }



}
